Simple application w/ Node.js + Koa + PostgreSQL

From Koa introduction:

Koa is a new web framework designed by the team behind Express, which aims to be a smaller, more expressive, and more robust foundation for web applications and APIs. Through leveraging generators Koa allows you to ditch callbacks and greatly increase error-handling. Koa does not bundle any middleware within core, and provides an elegant suite of methods that make writing servers fast and enjoyable.

Requirements

Koa requires Node 7.6.0 or higher for async/await syntax.
You can use older Node versions with Babel (see more about it at Koa installation section).
PostgreSQL version does not matter. We will use the latest one.

Environment

Node.js

If Node is not installed yet, you can download it here. If you are a lucky owner of Linux or macOS, package managers can be used - this method described here.
To check that the Node installation is correct, you can run the command:

1
$ node --version

That will print the Node version.
Also for NPM:

1
$ npm --version

Dependencies installation

Create directory where all the code will be located. Run terminal and open this directory.

Let’s initialize the package environment:

1
$ npm init

NPM will ask you a few questions. Type answers for package name of author.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
$ npm init

This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (ex) exampleapp
version: (1.0.0)
description: Example application on Koa and PostgreSQL
entry point: (index.js)
test command:
git repository:
keywords:
author: Nariman Safiulin <woofilee@gmail.com>
license: (ISC)
About to write to <..>\package.json:

{
"name": "exampleapp",
"version": "1.0.0",
"description": "Example application on Koa and PostgreSQL",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Nariman Safiulin <woofilee@gmail.com>",
"license": "ISC"
}


Is this ok? (yes)

You should see the package.json file that NPM has created.

Install koa:

1
$ npm i koa

Also we need something for requests routing. We will use a koa-router - popular and full-featured package.
Another one - koa-logger - for development logging.

1
$ npm i koa-router koa-logger

For database we will use a node-postgres driver. It’s a simple client, not a ORM.

1
$ npm i pg

PostgreSQL

You can download PostgreSQL here with a portable binaries for fast start w/o installation proccess.
To check the PostgreSQL installation, run the command:

1
$ sudo -u postgres psql

On Windows (type your own Windows user name instead of postgres, if you didn’t create a database manually):

1
> psql -U postgres

On Linux and macOS a PostgreSQL server should be running yet after installation via package manager.
Otherwise, or if you have Windows, follow next commands:

1
2
> initdb -U postgres -D data
> pg_ctl -D data start

A default postgres database username is recommended, data - a database storage directory, you can provide any other path.
After that a pg_ctl command will start the PostgreSQL server (provide a path to the database storage).

Check again, you should see a PostgreSQL prompt:

1
postgres=#

Type \q to exit.

Default database postgres was created for us.

Hello, World!

Create file app.js and copy the next code. It’s a modified version of standart Koa example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const Koa = require('koa');
const Router = require('koa-router');
const Logger = require('koa-logger');

const app = new Koa();
const router = new Router();

// Response to the World to the GET requests
router.get('/', async (ctx) => {
ctx.body = 'Hello, World!\n';
});

// Response by name to the GET requests, :name is URL fragment/argument
router.get('/:name', async (ctx) => {
ctx.body = `Hello, ${ctx.params.name}!\n`;
});

// Development logging
app.use(Logger());
// Add routes and response to the OPTIONS requests
app.use(router.routes()).use(router.allowedMethods());

// Listen the port
app.listen(3000, () => {
console.log('Server running on port 3000');
});

Now you can start the server:

1
$ node app.js

If the server has successfully started, open the browser and go to http://localhost:3000/. You should see the Hello, World! page. Also, try to type your name, for example, http://localhost:3000/Nariman.
In your terminal you should see something like that:

1
2
3
4
5
6
7
8
9
10
11
$ node app.js

Server running on port 3000
<-- GET /
--> GET / 200 13ms 14b
<-- GET /favicon.ico
--> GET /favicon.ico 200 7ms 20b
<-- GET /Nariman
--> GET /Nariman 200 10ms 16b
<-- GET /favicon.ico
--> GET /favicon.ico 200 7ms 20b

Let’s connect to the database.
We will use the connection pool, because it’s a common way to use database drivers, especially for PostgreSQL. Pool has advatages over manual connections, due to each new manual connection can take some time for connection establishment and it requires some management to control the number of simultaneous connections.

Add the dependency:

1
const { Pool } = require('pg');

Right before the server booting code (before app.listen call):

1
2
3
4
5
6
7
app.pool = new Pool({
user: 'postgres',
host: 'localhost',
database: 'postgres',
password: '', // Password is empty be default
port: 5432, // Default port
});

Then, change our routes, to query database for Hello string.

1
2
3
4
5
6
7
8
9
router.get('/', async (ctx) => {
const { rows } = await ctx.app.pool.query('SELECT $1::text as message', ['Hello, World!'])
ctx.body = rows[0].message;
});

router.get('/:name', async (ctx) => {
const { rows } = await ctx.app.pool.query('SELECT $1::text as message', [`Hello, ${ctx.params.name}!`])
ctx.body = rows[0].message;
});

Note that Koa can auto-translate the result into JSON, if the response is not a string. If you just return rows, you’ll see the JSON response.

Save and restart the server.

In conclusion

We wrote everything in one file. Of course, for a real project, you should create the project structure, and also take care of closing the PostgreSQL pool and Koa connections when shutting down the server.

You can also use other database libraries, like Sequelize, Bookshelf, Massive.

References